/*
*Copyright 2021-2023 NERCIS
*
*Licensed under the Apache License, Version 2.0 (the "License");
*you may not use this file except in compliance with the License.
*You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*Unless required by applicable law or agreed to in writing, software
*distributed under the License is distributed on an "AS IS" BASIS,
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*See the License for the specific language governing permissions and
*limitations under the License.
*/

package cn.ac.nercis.pes.community.controller.evaluation.planning;

import cn.ac.nercis.pes.common.constant.common.BaseConstants;
import cn.ac.nercis.pes.common.constant.knowledge.EvaluationMethod;
import cn.ac.nercis.pes.common.constant.knowledge.TargetType;
import cn.ac.nercis.pes.common.constant.project.FinishState;
import cn.ac.nercis.pes.community.component.dialog.MessageDialog;
import cn.ac.nercis.pes.community.component.dialog.MessageType;
import cn.ac.nercis.pes.community.constant.SaveMethod;
import cn.ac.nercis.pes.community.manager.RealTimeSaveManager;
import cn.ac.nercis.pes.community.support.event.CommonCallback;
import cn.ac.nercis.pes.community.utils.AppUtils;
import cn.ac.nercis.pes.community.utils.IconUtils;
import cn.ac.nercis.pes.community.utils.LogUtils;
import cn.ac.nercis.pes.community.utils.SpringUtils;
import cn.ac.nercis.pes.model.dto.evaluation.planning.AssetUnitEvalMethodDTO;
import cn.ac.nercis.pes.model.dto.knowledge.KmSimpleTargetDTO;
import cn.ac.nercis.pes.service.evaluation.EvaluationRangeService;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.net.URL;
import java.util.List;
import java.util.Objects;
import java.util.ResourceBundle;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 测评方式（快捷）内容管理控制器
 * @author zpy
 * @version 1.0.0
 */
@Slf4j
public class EvalMethodFastController implements Initializable {
    @FXML
    private StackPane page;
    @FXML
    private Button saveButton;
    @FXML
    private HBox evalMethodBox;
    @FXML
    private Label unitTargetLbl;
    @FXML
    private TextArea descTxt;

    private final EvaluationRangeService evaluationRangeService;
    private final ExecutorService executorService;
    private final RealTimeSaveManager realTimeSaveManager = new RealTimeSaveManager(this::realTimeSave);

    private String currentSystemId;
    private String currentAssetId;
    private KmSimpleTargetDTO currentLayerTarget;
    private String currentUnitTargetId;
    private AssetUnitEvalMethodDTO currentEvalMethod;
    private CommonCallback saveCallback;

    public EvalMethodFastController() {
        this.evaluationRangeService = SpringUtils.getBean(EvaluationRangeService.class);
        this.executorService = SpringUtils.getBean(ExecutorService.class);
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        saveButton.setGraphic(IconUtils.getGlyph("save-button-icon","btn-icon"));
        realTimeSaveManager.listenerCheckboxChange(this.findCheckBox());
        realTimeSaveManager.listenerTextChange(this.descTxt);
    }

    public void initializeData(String systemId, String assetId, KmSimpleTargetDTO layerTarget, String unitTargetId, CommonCallback saveCallback) {
        LogUtils.info(log, "初始化层面指标测评对象测试方式内容信息...");
        this.currentSystemId = systemId;
        this.currentAssetId = assetId;
        this.currentLayerTarget = layerTarget;
        this.currentUnitTargetId = unitTargetId;
        this.saveCallback = saveCallback;
        this.initCheckBox();
        this.loadEvaluationMethod();
    }

    @FXML
    public void onFinishSave() {
        LogUtils.info(log, "执行保存操作...");
        if(StringUtils.isBlank(currentUnitTargetId)){
            return;
        }
        saveEvaluationMethod(SaveMethod.SAVE, true);
    }

    public void realTimeSave(){
        LogUtils.info(log, "执行即时保存操作...");
        this.saveEvaluationMethod(SaveMethod.SAVE_NOW,true);
    }



    private void onEvaluationMethodClick(){
        this.saveEvaluationMethod(SaveMethod.SAVE_NOW, false);
    }

    public void saveEvaluationMethod(SaveMethod method, boolean finish) {
        String selectedMethod = getSelectedCheckBox();
        if (StringUtils.isBlank(selectedMethod)) {
            if(method != SaveMethod.SAVE_NOW){
                AppUtils.showMessageDialog("请选择测评方式",MessageType.WARN,Objects.requireNonNull(this.page));
            }
            return;
        }
        FinishState state = finish ? FinishState.FINISH : FinishState.INCOMPLETE;
        currentEvalMethod.setMethod(selectedMethod);
        currentEvalMethod.setDesc(descTxt.getText());
        LogUtils.info(log, "保存测评方式内容信息...");
        LogUtils.record(log, "请求数据，data：{},state:{}", currentEvalMethod, state);
        CompletableFuture.supplyAsync(() -> evaluationRangeService.saveUnitEvalMethod(currentEvalMethod, state),executorService)
                .thenAccept(res -> Platform.runLater(() -> {
                    if (res.isSuccess()) {
                        if (method == SaveMethod.SAVE) {
                            MessageDialog.builder()
                                    .withContainer(Objects.requireNonNull(this.page))
                                    .withType(MessageType.SUCCESS).withMessage("保存成功")
                                    .build().show();
                        }
                        if(Objects.nonNull(saveCallback)){
                            saveCallback.action();
                        }
                    } else {
                        if(method == SaveMethod.SAVE_NOW){
                            log.error("即时保存测评方式内容信息失败：{}",res.getMsg());
                        }else{
                            AppUtils.showMessageDialog(res.getMsg(),MessageType.FAIL,Objects.requireNonNull(page));
                        }
                    }
                }))
                .exceptionally((ex) -> {
                    log.error("保存测评方式内容信息出错!", ex);
                    return null;
                });
    }

    private String getSelectedCheckBox() {
        return this.findCheckBox().stream()
                .filter(CheckBox::isSelected)
                .map(CheckBox::getUserData)
                .map(String::valueOf)
                .collect(Collectors.joining(BaseConstants.MULTI_SPLIT_CHAR));
    }

    private void loadEvaluationMethod() {
        LogUtils.info(log, "获取测评方法信息...");
        LogUtils.record(log, "请求数据，systemId：{},assetId:{},unitTargetId:{}", this.currentSystemId, currentAssetId, currentUnitTargetId);
        CompletableFuture.supplyAsync(() -> evaluationRangeService.getUnitEvalMethod(this.currentSystemId,
                        currentAssetId, currentUnitTargetId),executorService)
                .thenAccept(res -> Platform.runLater(() -> {
                    if (res.isSuccess()) {
                        initEvaluationMethod(res.getData());
                    } else {
                        MessageDialog.builder()
                                .withContainer(this.page)
                                .withType(MessageType.FAIL)
                                .withMessage(res.getMsg())
                                .build().show();
                    }
                }))
                .exceptionally((ex) -> {
                    log.error("获取测评方法信息出错!", ex);
                    return null;
                });
    }

    private void initEvaluationMethod(AssetUnitEvalMethodDTO evalMethod){
        this.currentEvalMethod = evalMethod;
        this.unitTargetLbl.setText(evalMethod.getUnitTargetName());
        this.defaultSelectedCheckBox();
        this.descTxt.setText(StringUtils.isEmpty(evalMethod.getDesc()) ? "" : evalMethod.getDesc());
    }

    private void defaultSelectedCheckBox(){
        if(StringUtils.isBlank(currentEvalMethod.getMethod())){
            evalMethodBox.getChildren().stream()
                    .filter(n->n instanceof CheckBox)
                    .map(n->(CheckBox)n)
                    .forEach(cbx->cbx.setSelected(false));
        }else{
            String[] selected = StringUtils.split(currentEvalMethod.getMethod(), BaseConstants.MULTI_SPLIT_CHAR);
            evalMethodBox.getChildren().stream()
                    .filter(n->n instanceof CheckBox)
                    .map(n->(CheckBox)n)
                    .forEach(cbx->{
                        String method = String.valueOf(cbx.getUserData());
                        cbx.setSelected(StringUtils.containsAny(method,selected));
                    });
        }
    }

    private void initCheckBox() {
        if (currentLayerTarget.getType() == TargetType.TECHNOLOGY) {
            this.createCheckBox(EvaluationMethod.INTERVIEW, EvaluationMethod.DOCUMENT_REVIEW,
                    EvaluationMethod.FIELD_VIEW, EvaluationMethod.CONFIGURATION_CHECK,
                    EvaluationMethod.TOOLS_TESTING);
        } else {
            this.createCheckBox(EvaluationMethod.INTERVIEW, EvaluationMethod.DOCUMENT_REVIEW);
        }
    }

    private void createCheckBox(EvaluationMethod... methods){
        evalMethodBox.getChildren().clear();
        Stream.of(methods).forEach(em->{
            CheckBox cbx = new CheckBox();
            cbx.setUserData(em.getMethod());
            cbx.setText(em.getName());
            cbx.setOnAction(e->onEvaluationMethodClick());
            evalMethodBox.getChildren().add(cbx);
        });
    }

    private List<CheckBox> findCheckBox(){
        return evalMethodBox.getChildren().stream()
                .filter(n -> n instanceof CheckBox)
                .map(n -> (CheckBox) n)
                .toList();
    }

}